package cn.wink.springcloud.lb;

import lombok.Synchronized;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xw
 * @date 2020-05-10 16:57
 */
public class LoadBalancedImpl implements LoadBalanced {

    /**
     * 原子类记录访问次数
     */
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     *
     */
    private List<ServiceInstance> serviceInstances;

    /**
     * 服务名称
     */
    private String serviceName;

    /**
     * 服务发现：获得所有服务信息
     */
    private DiscoveryClient discoveryClient;

    private static LoadBalanced loadBalanced;

    @Synchronized
    public static LoadBalanced getOne(DiscoveryClient discoveryClient, String serviceName) {
        if (loadBalanced == null) {
            loadBalanced = new LoadBalancedImpl(discoveryClient, serviceName);
        }
        return loadBalanced;
    }

    private LoadBalancedImpl(DiscoveryClient discoveryClient, String serviceName) {
        this.serviceName = serviceName;
        this.discoveryClient = discoveryClient;
        this.serviceInstances = discoveryClient.getInstances(serviceName);
    }

    public final int getAndIncrement() {
        for (; ; ) {
            int current = atomicInteger.get();
            int next = current >= Integer.MAX_VALUE ? 0 : current + 1;
            //CAS自旋锁
            boolean b = atomicInteger.compareAndSet(current, next);
            if (b) {
                System.out.println("访问次数：next:" + next);
                return next;
            }
        }

    }


    /**
     * 负载均衡算法：rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标  ，每次服务重启动后rest接口计数从1开始。
     *
     * @return org.springframework.cloud.client.ServiceInstance
     * @author xw
     * @date 2020/5/10 16:58
     */
    @Override
    public ServiceInstance getInstances() {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}
